import Transform from "../common/transform";
import Aabb from "../common/aabb";
import Vec3 from "../common/vec3";
import Method from "../common/method";

export default class Shape {
    constructor(config) {
        this._id = -1;
        this._localTransform = new Transform();
        this._ptransform = new Transform();
        this._transform = new Transform();
        Method.combineMat3Vec3ToTransform(config.position,config.rotation,this._localTransform);
        Method.copyTransform(this._localTransform,this._ptransform);
        Method.copyTransform(this._localTransform,this._transform);
        this._restitution = config.restitution;
        this._friction = config.friction;
        this._density = config.density;
        this._geom = config.geometry;
        this._collisionGroup = config.collisionGroup;
        this._collisionMask = config.collisionMask;
        this._contactCallback = config.contactCallback;
        this._aabb = new Aabb();
        this._proxy = null;
        this.displacement = new Vec3();
        this._rigidBody=null;
        this._prev=null;
        this._next=null;
    }

    //.....................................public........................................

    get localTransform(){
        return this._localTransform;
    }

    //.....................................private........................................

    getFriction() {
        return this._friction;
    }
    setFriction(friction) {
        this._friction = friction;
    }
    getRestitution() {
        return this._restitution;
    }
    setRestitution(restitution) {
        this._restitution = restitution;
    }
    getLocalTransform() {
        return Method.copyTransform(this._localTransform,null);
    }
    getLocalTransformTo(transform) {
        Method.copyTransform(this._localTransform,transform);
    }
    getTransform() {
        return Method.copyTransform(this._transform,null);
    }
    getTransformTo(transform) {
        Method.copyTransform(this._transform,transform);
    }
    setLocalTransform(transform) {
        let _this = this._localTransform;
        Method.copyTransform(transform,_this);
        if(this._rigidBody != null) {
            let _this = this._rigidBody;
            _this.updateMass();
            let s = _this._shapeList;
            while(s != null) {
                let n = s._next;
                let tf1 = _this._ptransform.elements;
                let tf2 = _this._transform.elements;
                let dst = s._ptransform.elements;
                let src1 = s._localTransform.elements;
                dst[3] = tf1[3] * src1[3] + tf1[4] * src1[6] + tf1[5] * src1[9];
                dst[4] = tf1[3] * src1[4] + tf1[4] * src1[7] + tf1[5] * src1[10];
                dst[5] = tf1[3] * src1[5] + tf1[4] * src1[8] + tf1[5] * src1[11];
                dst[6] = tf1[6] * src1[3] + tf1[7] * src1[6] + tf1[8] * src1[9];
                dst[7] = tf1[6] * src1[4] + tf1[7] * src1[7] + tf1[8] * src1[10];
                dst[8] = tf1[6] * src1[5] + tf1[7] * src1[8] + tf1[8] * src1[11];
                dst[9] = tf1[9] * src1[3] + tf1[10] * src1[6] + tf1[11] * src1[9];
                dst[10] = tf1[9] * src1[4] + tf1[10] * src1[7] + tf1[11] * src1[10];
                dst[11] = tf1[9] * src1[5] + tf1[10] * src1[8] + tf1[11] * src1[11];
                dst[0] = tf1[3] * src1[0] + tf1[4] * src1[1] + tf1[5] * src1[2];
                dst[1] = tf1[6] * src1[0] + tf1[7] * src1[1] + tf1[8] * src1[2];
                dst[2] = tf1[9] * src1[0] + tf1[10] * src1[1] + tf1[11] * src1[2];
                dst[0] += tf1[0];dst[1] += tf1[1];dst[2] += tf1[2];
                let dst1 = s._transform.elements;
                let src11 = s._localTransform.elements;
                dst1[3] = tf2[3] * src11[3] + tf2[4] * src11[6] + tf2[5] * src11[9];
                dst1[4] = tf2[3] * src11[4] + tf2[4] * src11[7] + tf2[5] * src11[10];
                dst1[5] = tf2[3] * src11[5] + tf2[4] * src11[8] + tf2[5] * src11[11];
                dst1[6] = tf2[6] * src11[3] + tf2[7] * src11[6] + tf2[8] * src11[9];
                dst1[7] = tf2[6] * src11[4] + tf2[7] * src11[7] + tf2[8] * src11[10];
                dst1[8] = tf2[6] * src11[5] + tf2[7] * src11[8] + tf2[8] * src11[11];
                dst1[9] = tf2[9] * src11[3] + tf2[10] * src11[6] + tf2[11] * src11[9];
                dst1[10] = tf2[9] * src11[4] + tf2[10] * src11[7] + tf2[11] * src11[10];
                dst1[11] = tf2[9] * src11[5] + tf2[10] * src11[8] + tf2[11] * src11[11];
                dst1[0] = tf2[3] * src11[0] + tf2[4] * src11[1] + tf2[5] * src11[2];
                dst1[1] = tf2[6] * src11[0] + tf2[7] * src11[1] + tf2[8] * src11[2];
                dst1[2] = tf2[9] * src11[0] + tf2[10] * src11[1] + tf2[11] * src11[2];
                dst1[0] += tf2[0];dst1[1] += tf2[1];dst1[2] += tf2[2];
                s._geom._computeAabb(s._aabb,s._ptransform);
                let aabb=s._aabb.elements;
                let minX = aabb[0],minY = aabb[1],minZ = aabb[2];
                let maxX = aabb[3],maxY = aabb[4],maxZ = aabb[5];
                s._geom._computeAabb(s._aabb,s._transform);
                aabb[0] = minX < aabb[0] ? minX : aabb[0];aabb[1] = minY < aabb[1] ? minY : aabb[1];aabb[2] = minZ < aabb[2] ? minZ : aabb[2];
                aabb[3] = maxX > aabb[3] ? maxX : aabb[3];aabb[4] = maxY > aabb[4] ? maxY : aabb[4];aabb[5] = maxZ > aabb[5] ? maxZ : aabb[5];
                if(s._proxy != null) {
                    let v = s.displacement.elements,transform=s._transform.elements,ptransform=s._ptransform.elements;
                    v[0] = transform[0] - ptransform[0];v[1] = transform[1] - ptransform[1];v[2] = transform[2] - ptransform[2];
                    s._rigidBody._world._broadPhase.moveProxy(s._proxy,s._aabb,s.displacement);
                }
                s = n;
            }
        }
    }
    getDensity() {
        return this._density;
    }
    setDensity(density) {
        this._density = density;
        if(this._rigidBody != null) {
            let _this = this._rigidBody;
            _this.updateMass();
            let s = _this._shapeList;
            while(s != null) {
                let n = s._next;
                let tf1 = _this._ptransform.elements;
                let tf2 = _this._transform.elements;
                let dst = s._ptransform.elements;
                let src1 = s._localTransform.elements;
                dst[3] = tf1[3] * src1[3] + tf1[4] * src1[6] + tf1[5] * src1[9];
                dst[4] = tf1[3] * src1[4] + tf1[4] * src1[7] + tf1[5] * src1[10];
                dst[5] = tf1[3] * src1[5] + tf1[4] * src1[8] + tf1[5] * src1[11];
                dst[6] = tf1[6] * src1[3] + tf1[7] * src1[6] + tf1[8] * src1[9];
                dst[7] = tf1[6] * src1[4] + tf1[7] * src1[7] + tf1[8] * src1[10];
                dst[8] = tf1[6] * src1[5] + tf1[7] * src1[8] + tf1[8] * src1[11];
                dst[9] = tf1[9] * src1[3] + tf1[10] * src1[6] + tf1[11] * src1[9];
                dst[10] = tf1[9] * src1[4] + tf1[10] * src1[7] + tf1[11] * src1[10];
                dst[11] = tf1[9] * src1[5] + tf1[10] * src1[8] + tf1[11] * src1[11];
                dst[0] = tf1[3] * src1[0] + tf1[4] * src1[1] + tf1[5] * src1[2];
                dst[1] = tf1[6] * src1[0] + tf1[7] * src1[1] + tf1[8] * src1[2];
                dst[2] = tf1[9] * src1[0] + tf1[10] * src1[1] + tf1[11] * src1[2];
                dst[0] += tf1[0];dst[1] += tf1[1];dst[2] += tf1[2];
                let dst1 = s._transform.elements;
                let src11 = s._localTransform.elements;
                dst1[3] = tf2[3] * src11[3] + tf2[4] * src11[6] + tf2[5] * src11[9];
                dst1[4] = tf2[3] * src11[4] + tf2[4] * src11[7] + tf2[5] * src11[10];
                dst1[5] = tf2[3] * src11[5] + tf2[4] * src11[8] + tf2[5] * src11[11];
                dst1[6] = tf2[6] * src11[3] + tf2[7] * src11[6] + tf2[8] * src11[9];
                dst1[7] = tf2[6] * src11[4] + tf2[7] * src11[7] + tf2[8] * src11[10];
                dst1[8] = tf2[6] * src11[5] + tf2[7] * src11[8] + tf2[8] * src11[11];
                dst1[9] = tf2[9] * src11[3] + tf2[10] * src11[6] + tf2[11] * src11[9];
                dst1[10] = tf2[9] * src11[4] + tf2[10] * src11[7] + tf2[11] * src11[10];
                dst1[11] = tf2[9] * src11[5] + tf2[10] * src11[8] + tf2[11] * src11[11];
                dst1[0] = tf2[3] * src11[0] + tf2[4] * src11[1] + tf2[5] * src11[2];
                dst1[1] = tf2[6] * src11[0] + tf2[7] * src11[1] + tf2[8] * src11[2];
                dst1[2] = tf2[9] * src11[0] + tf2[10] * src11[1] + tf2[11] * src11[2];
                dst1[0] += tf2[0];dst1[1] += tf2[1];dst1[2] += tf2[2];
                s._geom._computeAabb(s._aabb,s._ptransform);
                let aabb=s._aabb.elements;
                let minX = aabb[0],minY = aabb[1],minZ = aabb[2];
                let maxX = aabb[3],maxY = aabb[4],maxZ = aabb[5];
                s._geom._computeAabb(s._aabb,s._transform);
                aabb[0] = minX < aabb[0] ? minX : aabb[0];aabb[1] = minY < aabb[1] ? minY : aabb[1];aabb[2] = minZ < aabb[2] ? minZ : aabb[2];
                aabb[3] = maxX > aabb[3] ? maxX : aabb[3];aabb[4] = maxY > aabb[4] ? maxY : aabb[4];aabb[5] = maxZ > aabb[5] ? maxZ : aabb[5];
                if(s._proxy != null) {
                    let v = s.displacement.elements,transform=this._transform.elements,ptransform=this._ptransform.elements;
                    v[0] = transform[0] - ptransform[0];v[1] = transform[1] - ptransform[1];v[2] = transform[2] - ptransform[2];
                    s._rigidBody._world._broadPhase.moveProxy(s._proxy,s._aabb,s.displacement);
                }
                s = n;
            }
        }
    }
    getAabb() {
        return Method.copyAabb(this._aabb,null);
    }
    getAabbTo(aabb) {
        Method.copyAabb(this._aabb,aabb);
    }
    getGeometry() {
        return this._geom;
    }
    getRigidBody() {
        return this._rigidBody;
    }
    getCollisionGroup() {
        return this._collisionGroup;
    }
    setCollisionGroup(collisionGroup) {
        this._collisionGroup = collisionGroup;
    }
    getCollisionMask() {
        return this._collisionMask;
    }
    setCollisionMask(collisionMask) {
        this._collisionMask = collisionMask;
    }
    getContactCallback() {
        return this._contactCallback;
    }
    setContactCallback(callback) {
        this._contactCallback = callback;
    }
    getPrev() {
        return this._prev;
    }
    getNext() {
        return this._next;
    }
}